<?php

/*
 * Copyright 2008 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#namespace tehframework\routing;

#use tehframework\request\Request;
#use tehframework\response\Response;

abstract class RouteBase implements Route
{
	/**
	 * @var EventHandler<RouteBuildEventArgs>
	 */
	public $onBuild;
	
	/**
	 * @var EventHandler<RouteMatchResultEventArgs>
	 */
	public $onMatched;
	
	/**
	 * @var EventHandler<RouteMatchResultEventArgs>
	 */
	public $onNotMatched;
	
	public function __construct()
	{
		$this->onMatched    = new EventHandlerImpl();
		$this->onNotMatched = new EventHandlerImpl();
		$this->onBuild      = new EventHandlerImpl();
	}
	
	/**
	 * @param  array<string,string> $args
	 * @param  array<string,mixed> $opts
	 * @param  Request? $request
	 * @return string
	 */
	public function build(array $args, array $opts, Request $request = null)
	{
		if (count($this->onBuild))
		{
			$this->onBuild(new RouteBuildEventArgs($this, $args, $opts, $request));
		}
		
		return $this->doBuild($args, $opts, $request);
	}
	
	/**
	 * @param  Request $request
	 * @param  Response $response
	 * @return Route::RESULT_*
	 */
	public function match(Request $request, Response $response)
	{
		$result = $this->doMatch($request, $response);
		
		switch ($result)
		{
			case Route::RESULT_MATCH:
			case Route::RESULT_CONTINUE:
			{
				if (!count($this->onMatched))
				{
					return $result;
				}
				
				$this->onMatched(
					new RouteMatchResultEventArgs($result, $this, $request, $response)
				);
				
				break;
			}
			
			case Route::RESULT_NO_MATCH:
			{
				if (!count($this->onNotMatched))
				{
					return $result;
				}
				
				$this->onNotMatched(
					new RouteMatchResultEventArgs($result, $this, $request, $response)
				);
				
				break;
			}
		}
		
		return $e->getResult();
	}
	
	/**
	 * @param  RouteBuildEventArgs $e
	 */
	protected function onBuild(RouteBuildEventArgs $e)
	{
		$this->onBuild->fireEvent($this, $e);
	}
	
	/**
	 * @param  RouteMatchResultEventArgs $e
	 */
	protected function onMatched(RouteMatchResultEventArgs $e)
	{
		$this->onMatched->fireEvent($this, $e);
	}
	
	/**
	 * @param  RouteMatchResultEventArgs $e
	 */
	protected function onNotMatched(RouteMatchResultEventArgs $e)
	{
		$this->onNotMatched->fireEvent($this, $e);
	}
	
	/**
	 * @param  array<string,string> $args
	 * @param  array<string,mixed> $opts
	 * @param  Request? $request
	 * @return string
	 */
	abstract protected function doBuild(
		array $args, array $opts, Request $request = null);
	
	/**
	 * @param  Request $request
	 * @param  Response $response
	 * @return Route::RESULT_*
	 */
	abstract protected function doMatch(Request $request, Response $response);
}